// Tencent is pleased to support the open source community by making Mars available.
// Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.

// Licensed under the MIT License (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://opensource.org/licenses/MIT

// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing permissions and
// limitations under the License.


/*
 * longlink_packer.cc
 *
 *  Created on: 2012-7-18
 *      Author: yerungui, caoshaokun
 */

#include "longlink_packer.h"

#ifndef WIN32
#include <arpa/inet.h>
#endif // !WIN32

#ifdef __APPLE__
#include "mars/xlog/xlogger.h"
#else
#include "mars/comm/xlogger/xlogger.h"
#endif
#include "mars/comm/autobuffer.h"
#include "mars/stn/stn.h"

//客户端发送的心跳请求
#define NOOP_CMDID 1
//服务端响应的心跳
#define NOOP_CMDID_RESP 100

//客户端发送登录后,服务端响应
#define LOGIN_CMDID_FAIL_RESP 2103
#define LOGIN_CMDID_SUCCESS_RESP 2104

//该功能不主动调用不会触发。
#define SIGNALKEEP_CMDID 243

//目前所有服务端发送(响应)的消息,都当成是push
#define PUSH_DATA_TASKID 0

static uint32_t sg_client_version = 0;

//消息头长度
static size_t head_len = 9;

//心跳间隔时间ms
static uint32_t noop_interval = 20*1000;

#pragma pack(push, 1)
struct __STNetMsgXpHeader {
    //下面定义的顺序决定了tcp传输的顺序,服务端收到的bytes与下面赋值顺序一致(已经验证过)
    //消息头9个字节
    //消息ID
    uint32_t    cmdid;
    //扩展字段:暂时没用到
    int8_t    extension;
    //消息长度
    uint32_t    body_length;
};
#pragma pack(pop)

namespace mars {
namespace stn {
longlink_tracker* (*longlink_tracker::Create)()
= []() {
    return new longlink_tracker;
};
    
void SetClientVersion(uint32_t _client_version)  {
    sg_client_version = _client_version;
}

/*解析接收到的包 */
static int __unpack_test(const void* _packed, size_t _packed_len, uint32_t& _cmdid, uint32_t& _seq, size_t& _package_len, size_t& _body_len) {
    __STNetMsgXpHeader st = {0};
   
    if (_packed_len < head_len) {
        _package_len = 0;
        _body_len = 0;
        return LONGLINK_UNPACK_CONTINUE;
    }
    
    memcpy(&st, _packed, head_len);
    
    //ntohl()指的是ntohl函数，是将一个无符号长整形数从网络字节顺序转换为主机字节顺序，
    //ntohl()返回一个以主机字节顺序表达的数
    //网络字节顺序 :参考https://baike.baidu.com/item/%E5%AD%97%E8%8A%82%E9%A1%BA%E5%BA%8F
    _cmdid = ntohl(st.cmdid);
    if (_cmdid == NOOP_CMDID_RESP) {
        //心跳响应包,设置taskID为默认值,方便mars处理心跳逻辑
        _seq = Task::kNoopTaskID;
        xdebug2(TSF"rishli __unpack_test: this is noop resp");
    }
    else if (_cmdid == LOGIN_CMDID_FAIL_RESP || _cmdid == LOGIN_CMDID_SUCCESS_RESP) {
        //客户端的登录鉴权响应
        _seq = Task::kLongLinkIdentifyCheckerTaskID;
        xdebug2(TSF"rishli __unpack_test: this is login resp");
    }
    else {
        //数据包:设置taskId为cmdid,方便后面处理逻辑
        _seq = ntohl(st.cmdid);
        xdebug2(TSF"rishli __unpack_test: this is data pkg");
    }
    
    _body_len = ntohl(st.body_length);
    _package_len = head_len + _body_len;

    xdebug2(TSF"rishli2 __unpack_test:cmdid %_,taskid %_,package_size %_", _cmdid, _seq, _body_len);

    if (_package_len > 1024*1024) { return LONGLINK_UNPACK_FALSE; }
    if (_package_len > _packed_len) { return LONGLINK_UNPACK_CONTINUE; }

    return LONGLINK_UNPACK_OK;
}

void (*longlink_pack)(uint32_t _cmdid, uint32_t _seq, const AutoBuffer& _body, const AutoBuffer& _extension, AutoBuffer& _packed, longlink_tracker* _tracker)
= [](uint32_t _cmdid, uint32_t _seq, const AutoBuffer& _body, const AutoBuffer& _extension, AutoBuffer& _packed, longlink_tracker* _tracker) {

    xdebug2(TSF"rishli _longlink_pack:cmdid %_,taskid %_,package_size %_", _cmdid, _seq, _body.Length());

    if (_seq == Task::kNoopTaskID) {
        //心跳包:mars内部维护
        __STNetMsgXpHeader st = { 0 };
        st.cmdid = htonl(_cmdid);
        st.extension = htonl(0);
        st.body_length = htonl(0);

        _packed.AllocWrite(head_len);
        _packed.Write(&st, head_len);

        xdebug2(TSF"rishli __longlink_pack: this is noop req pkg");
    }
    else
    {
        //消息头已经在java层封装到了body
        _packed.AllocWrite(_body.Length());
        _packed.Write(_body.Ptr(), _body.Length());
    }
    _packed.Seek(0, AutoBuffer::ESeekStart);
};


int (*longlink_unpack)(const AutoBuffer& _packed, uint32_t& _cmdid, uint32_t& _seq, size_t& _package_len, AutoBuffer& _body, AutoBuffer& _extension, longlink_tracker* _tracker)
= [](const AutoBuffer& _packed, uint32_t& _cmdid, uint32_t& _seq, size_t& _package_len, AutoBuffer& _body, AutoBuffer& _extension, longlink_tracker* _tracker) {
   size_t body_len = 0;

   int ret = __unpack_test(_packed.Ptr(), _packed.Length(), _cmdid,  _seq, _package_len, body_len);
    
   xdebug2(TSF"rishli _longlink_unpack:cmdid %_,taskid %_,package_size %_", _cmdid, _seq, _body.Length());

    if (LONGLINK_UNPACK_OK != ret) return ret;
    
    //消息头+消息内容,全部回调到java
    _body.Write(AutoBuffer::ESeekCur, _packed.Ptr(0), _package_len);
    
    return ret;
};



uint32_t (*longlink_noop_cmdid)()
= []() -> uint32_t {
    return NOOP_CMDID;
};

bool  (*longlink_noop_isresp)(uint32_t _taskid, uint32_t _cmdid, uint32_t _recv_seq, const AutoBuffer& _body, const AutoBuffer& _extend)
= [](uint32_t _taskid, uint32_t _cmdid, uint32_t _recv_seq, const AutoBuffer& _body, const AutoBuffer& _extend) {
    return NOOP_CMDID_RESP == _cmdid;
};

uint32_t (*signal_keep_cmdid)()
= []() -> uint32_t {
    return SIGNALKEEP_CMDID;
};

void (*longlink_noop_req_body)(AutoBuffer& _body, AutoBuffer& _extend)
= [](AutoBuffer& _body, AutoBuffer& _extend) {
    
};
    
void (*longlink_noop_resp_body)(const AutoBuffer& _body, const AutoBuffer& _extend)
= [](const AutoBuffer& _body, const AutoBuffer& _extend) {
    
};

//心跳间隔ms:设置为0,就使用mars自带的智能心跳
uint32_t (*longlink_noop_interval)()
= []() -> uint32_t {
    return noop_interval;
};

bool (*longlink_complexconnect_need_verify)()
= []() {
    return false;
};

bool (*longlink_ispush)(uint32_t _cmdid, uint32_t _taskid, const AutoBuffer& _body, const AutoBuffer& _extend)
= [](uint32_t _cmdid, uint32_t _taskid, const AutoBuffer& _body, const AutoBuffer& _extend) {
    return true;
};
    

///判断当前包是否是登录鉴权响应,如果返回true,会回调java onLongLinkIdentifyResp()方法,false:当成普通push包处理
bool (*longlink_identify_isresp)(uint32_t _sent_seq, uint32_t _cmdid, uint32_t _recv_seq, const AutoBuffer& _body, const AutoBuffer& _extend)
= [](uint32_t _sent_seq, uint32_t _cmdid, uint32_t _recv_seq, const AutoBuffer& _body, const AutoBuffer& _extend) {
    xdebug2(TSF"rishli _longlink_identify_isresp:cmdid %_,_sent_seq %_,_recv_seq %_", _cmdid, _sent_seq, _recv_seq);
    return _sent_seq == _recv_seq && 0 != _sent_seq;
};

}
}
